package com.smedi.ismedi.inmail.core.port.adapter.restful;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.smedi.ismedi.cache.starter.util.IdempotenceLock;
import com.smedi.ismedi.file.dto.response.FileInfoResponse;
import com.smedi.ismedi.inmail.api.dto.request.*;
import com.smedi.ismedi.inmail.api.dto.response.*;
import com.smedi.ismedi.inmail.api.feign.RemoteAnnouncementFeignApi;
import com.smedi.ismedi.inmail.core.application.command.*;
import com.smedi.ismedi.inmail.core.application.query.AnnouncementQueryService;
import com.smedi.ismedi.inmail.core.application.service.AnnouncementApplicationService;
import com.smedi.ismedi.inmail.core.domain.aggregatemodel.Node;
import com.smedi.ismedi.inmail.core.domain.aggregatemodel.announcement.Announcement;
import com.smedi.ismedi.inmail.core.domain.aggregatemodel.announcement.AttachmentKeyAndTime;
import com.smedi.ismedi.inmail.core.domain.dto.ReadRecord;
import com.smedi.ismedi.inmail.core.domain.repository.AttachmentRepository;
import com.smedi.ismedi.inmail.core.port.adapter.convert.AdapterConverter;
import com.smedi.ismedi.inmail.core.port.adapter.persistence.mybatis.mapper.AnnouncementReadRecordRelationshipMapper;
import com.smedi.ismedi.inmail.core.port.adapter.service.AuthorityRoleManagementRemoteApiService;
import com.smedi.ismedi.inmail.core.port.adapter.service.PersonRemoteApi;
import com.smedi.ismedi.web.starter.common.PaginationData;
import com.smedi.ismedi.web.starter.common.ResponseData;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * 通知公告Controller
 *
 * @author jiangqinxuan
 * @date 2021/07/26
 */
@AllArgsConstructor
@RestController
public class AnnouncementController implements RemoteAnnouncementFeignApi {
    private final AnnouncementApplicationService announcementApplicationService;

    private final AnnouncementQueryService announcementQueryService;

    private final PersonRemoteApi personRemoteApi;

    private final AttachmentRepository attachmentRepository;

    private final AnnouncementReadRecordRelationshipMapper announcementReadRecordRelationshipMapper;

    private final AdapterConverter adapterConverter;

    private final AuthorityRoleManagementRemoteApiService authorityRoleManagementRemoteApiService;

    @Override
    @IdempotenceLock
    public ResponseData<AnnouncementResponse> createAnnouncement(AnnouncementCreateRequest announcementCreateRequest) {
        AnnouncementCreateCommand announcementCreateCommand = adapterConverter.announcementCreateRequestToAnnouncementCreateCommand(announcementCreateRequest);

        Announcement announcement = announcementApplicationService.createAnnouncement(announcementCreateCommand);
        AnnouncementResponse announcementResponse = adapterConverter.announcementToAnnouncementResponse(announcement);

        return new ResponseData<AnnouncementResponse>().success(announcementResponse);
    }

    @Override
    @IdempotenceLock
    public ResponseData<AnnouncementResponse> editAnnouncement(AnnouncementEditRequest announcementEditRequest) {
        AnnouncementEditCommand announcementEditCommand = adapterConverter.announcementEditRequestToAnnouncementEditCommand(announcementEditRequest);

        Announcement announcement = announcementApplicationService.editAnnouncement(announcementEditCommand);
        AnnouncementResponse announcementResponse = adapterConverter.announcementToAnnouncementResponse(announcement);

        return new ResponseData<AnnouncementResponse>().success(announcementResponse);
    }

    @Override
    @IdempotenceLock
    public ResponseData<AnnouncementResponse> reviewAnnouncement(AnnouncementReviewRequest announcementReviewRequest) {
        AnnouncementReviewCommand announcementReviewCommand = adapterConverter.announcementReviewRequestToAnnouncementReviewCommand(announcementReviewRequest);

        Announcement announcement = announcementApplicationService.reviewAnnouncement(announcementReviewCommand);
        AnnouncementResponse announcementResponse = adapterConverter.announcementToAnnouncementResponse(announcement);

        return new ResponseData<AnnouncementResponse>().success(announcementResponse);
    }

    @Override
    @IdempotenceLock
    public ResponseData<AnnouncementResponse> disableAnnouncement(AnnouncementDisableRequest announcementDisableRequest) {
        AnnouncementDisableCommand announcementDisableCommand = adapterConverter.announcementDisableRequestToAnnouncementDisableCommand(announcementDisableRequest);

        Announcement announcement = announcementApplicationService.disableAnnouncement(announcementDisableCommand);
        AnnouncementResponse announcementResponse = adapterConverter.announcementToAnnouncementResponse(announcement);

        return new ResponseData<AnnouncementResponse>().success(announcementResponse);
    }

    @Override
    public ResponseEntity<byte[]> postDownloadFilesToZip(List<String> attachmentKeyList) throws IOException {
        HttpHeaders headers = new HttpHeaders();

        headers.setContentDispositionFormData("attachment", new String(DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now()).getBytes(), StandardCharsets.ISO_8859_1) + ".zip");
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        byte[] bytes = announcementApplicationService.downloadFilesToZip(attachmentKeyList);
        return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
    }

    @Override
    public ResponseData<FileResponse> postDownloadFilesSetNameToZip(DownloadFileToZipRequest downloadFileToZipRequest) throws IOException {
        DownloadFileToZipCommand downloadFileToZipCommand = adapterConverter.downloadFileToZipRequestToDownloadFileToZipCommand(downloadFileToZipRequest);
        List<AttachmentKeyAndTime> attachmentKeyList = announcementQueryService.getAttachmentKeyList(downloadFileToZipCommand);
        FileInfoResponse fileInfoResponse = announcementApplicationService.postDownloadFilesSetNameToZip(attachmentKeyList);
        return new ResponseData<FileInfoResponse>().success(adapterConverter.fileInfoResponseToFileResponse(fileInfoResponse));
    }

    @Override
    public ResponseData<AnnouncementResponse> getAnnouncementOne(AnnouncementOneQueryRequest announcementOneQueryRequest) {
        AnnouncementReadCommand announcementReadCommand = adapterConverter.announcementOneQueryRequestToAnnouncementReadCommand(announcementOneQueryRequest);
        Announcement announcement = announcementApplicationService.readAnnouncement(announcementReadCommand);
        AnnouncementResponse announcementResponse = adapterConverter.announcementToAnnouncementResponse(announcement);
        return new ResponseData<>().success(announcementResponse);
    }

    @Override
    public ResponseData<List<AnnouncementResponse>> getAnnouncementList(AnnouncementListQueryRequest announcementListQueryRequest) {
        AnnouncementListQuery announcementListQuery = adapterConverter.announcementListQueryRequestToAnnouncementListQuery(announcementListQueryRequest);
        List<Announcement> announcements = announcementQueryService.getAnnouncementList(announcementListQuery);
        List<AnnouncementResponse> announcementResponses = adapterConverter.announcementToAnnouncementResponse(announcements);
        return new ResponseData<PaginationData<AnnouncementManagementResponse>>().success(announcementResponses);
    }

    @Override
    public ResponseData<PaginationData<AnnouncementResponse>> getAnnouncementPageInManagement(AnnouncementPageQueryRequest announcementPageQueryRequest) {
        AnnouncementPageQuery announcementPageQuery = adapterConverter.announcementPageQueryRequestToAnnouncementPageQuery(announcementPageQueryRequest);
        Page<Announcement> announcementPage = announcementQueryService.getAnnouncementPageInManagement(announcementPageQuery);
        return new ResponseData<PaginationData<AnnouncementManagementResponse>>().success(adapterConverter.announcementPageToAnnouncementResponsePaginationData(announcementPage));
    }

    @Override
    public ResponseData<PaginationData<AnnouncementResponse>> getAnnouncementPageInPerson(AnnouncementPageQueryRequest announcementPageQueryRequest) {
        AnnouncementPageQuery announcementPageQuery = adapterConverter.announcementPageQueryRequestToAnnouncementPageQuery(announcementPageQueryRequest);
        Page<Announcement> announcementPage = announcementQueryService.getAnnouncementPageInPerson(announcementPageQuery);
        return new ResponseData<PaginationData<AnnouncementManagementResponse>>().success(adapterConverter.announcementPageToAnnouncementResponsePaginationData(announcementPage));
    }

    @Override
    public ResponseData<PaginationData<AnnouncementResponse>> getAnnouncementPage(AnnouncementPageQueryRequest announcementPageQueryRequest) {
        AnnouncementPageQuery announcementPageQuery = adapterConverter.announcementPageQueryRequestToAnnouncementPageQuery(announcementPageQueryRequest);
        Page<Announcement> announcementPage = announcementQueryService.getAnnouncementPage(announcementPageQuery);
        return new ResponseData<PaginationData<AnnouncementManagementResponse>>().success(adapterConverter.announcementPageToAnnouncementResponsePaginationData(announcementPage));

    }

    @Override
    public ResponseData<NodeResponse> getOrganizationTree() {
        Node organizationTree = personRemoteApi.getOrganizationTree();
        return new ResponseData<>().success(adapterConverter.nodeToNodeResponse(organizationTree));
    }

    @Override
    public ResponseData<NodeResponse> getProjectTree() {
        Node projectTree = personRemoteApi.getProjectTree();
        return new ResponseData<>().success(adapterConverter.nodeToNodeResponse(projectTree));
    }

    @Override
    public ResponseData<Boolean> updateReadRecord(AnnouncementReadRecordRequest announcementReadRecordRequest) throws IOException {
        AnnouncementReadRecordCommand announcementReadRecordCommand = adapterConverter.announcementReadRecordRequestToAnnouncementReadRecordCommand(announcementReadRecordRequest);

        announcementApplicationService.updateReadRecord(announcementReadRecordCommand);

        return new ResponseData<>().success(true);
    }

    @Override
    public ResponseData<Boolean> getAccessToIncrease() {
        return new ResponseData<>().success(authorityRoleManagementRemoteApiService.getAccessToIncrease());
    }

    @Override
    @IdempotenceLock
    public ResponseData<Boolean> removeAnnouncement(AnnouncementRemoveRequest announcementRemoveRequest) {
        AnnouncementRemoveCommand announcementRemoveCommand = adapterConverter.announcementRemoveRequestToAnnouncementRemoveCommand(announcementRemoveRequest);

        announcementApplicationService.removeAnnouncement(announcementRemoveCommand);

        return new ResponseData<AnnouncementResponse>().success(true);
    }

    @Override
    public ResponseData<String> getReadRecordOne(ReadRecordOneQueryRequest readRecordOneQueryRequest) throws IOException {
        ReadRecordOneQueryCommand readRecordOneQueryCommand = adapterConverter.readRecordOneQueryRequestToReadRecordOneQueryCommand(readRecordOneQueryRequest);
        String url = announcementApplicationService.getReadRecordOne(readRecordOneQueryCommand).getUrlOut();
        return new ResponseData<>().success(url);
    }

    @Override
    public ResponseData<String> downloadReadRecordOne(ReadRecordOneQueryRequest readRecordOneQueryRequest) throws IOException {
        ReadRecordOneQueryCommand readRecordOneQueryCommand = adapterConverter.readRecordOneQueryRequestToReadRecordOneQueryCommand(readRecordOneQueryRequest);
        String url = announcementApplicationService.getReadRecordOne(readRecordOneQueryCommand).getUrlIn();
        return new ResponseData<>().success(url);
    }

    @Override
    public ResponseData<ReadRecordResponse> getAllReadRecordZip(ReadRecordAllZipRequest readRecordAllZipRequest) {
        ReadRecordAllZipQueryCommand readRecordAllZipQueryCommand = adapterConverter.readRecordAllZipRequestToReadRecordAllZipQueryCommand(readRecordAllZipRequest);
        ReadRecord readRecord = announcementApplicationService.getAllReadRecordZip(readRecordAllZipQueryCommand);
        ReadRecordResponse readRecordResponse = adapterConverter.readRecordToReadRecordResponse(readRecord);
        return new ResponseData<>().success(readRecordResponse);
    }

    @Override
    public ResponseData<String> exportAnnouncement(AnnouncementExportRequest announcementExportRequest) {
        AnnouncementListQuery announcementListQuery = adapterConverter.announcementExportRequestToAnnouncementListQuery(announcementExportRequest);
        List<Announcement> announcements = announcementQueryService.getAnnouncementListInManagement(announcementListQuery);
        return new ResponseData<>().success(announcementApplicationService.exportAnnouncement(announcements));
    }
}
